package moonlit.chill.pay.service.impl.wechat;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import lombok.extern.slf4j.Slf4j;
import moonlit.chill.pay.cache.PayConfigDataCache;
import moonlit.chill.pay.constants.Constants;
import moonlit.chill.pay.service.PayStrategy;
import moonlit.chill.pay.util.WxConfigUtil;
import moonlit.chill.pay.vo.PayConfig;
import moonlit.chill.pay.vo.PayResult;
import moonlit.chill.pay.vo.RefundResult;
import moonlit.chill.pay.vo.TradeParam;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author MoonlitChill
 * @date 2024/4/16 15:08
 */
@Slf4j
@Service("wxRefundStrategy")
public class WxRefundStrategyServiceImpl implements PayStrategy {

    @Resource
    private PayConfigDataCache payConfigDataCache;

    @Autowired
    private WxConfigUtil wxConfigUtil;

    private static final String TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";

    @NotNull
    private static CreateRequest getCreateRequest(TradeParam tradeParam) {
        CreateRequest param = new CreateRequest();
        param.setOutTradeNo(tradeParam.getTransNum());
        param.setOutRefundNo(tradeParam.getRefundNo());
        AmountReq amount = new AmountReq();
        amount.setRefund(tradeParam.getRefundFee().multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue());
        amount.setTotal(tradeParam.getTotalFee().multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue());
        amount.setCurrency("CNY");
        param.setAmount(amount);
        return param;
    }

    @Override
    public PayResult<?> payForRefund(TradeParam tradeParam) {
        log.info("微信退款参数：{}", JSONUtil.toJsonStr(tradeParam));
        PayResult<String> result = new PayResult<>();
        try {
            PayConfig payConfig = payConfigDataCache.getPayConfig();
            Config config = wxConfigUtil.getConfig(payConfig);
            RefundService service = new RefundService.Builder().config(config).build();
            CreateRequest param = getCreateRequest(tradeParam);
            log.info("微信退款请求参数：{}", JSONUtil.toJsonStr(param));
            Refund refund = service.create(param);
            log.info("微信退款响应参数：{}", JSONUtil.toJsonStr(refund));
            if (ObjectUtil.isNotEmpty(refund)) {
                RefundResult refundResult = new RefundResult();
                Status status = refund.getStatus();
                refundResult.setRefundStatus(refund.getStatus().name());
                refundResult.setTransNum(refund.getOutTradeNo());
                refundResult.setRefundNo(refund.getOutRefundNo());
                refundResult.setOutTradeNo(refund.getTransactionId());
                refundResult.setOutRefundNo(refund.getRefundId());
                Long refundFee = refund.getAmount().getRefund();
                BigDecimal amountPay = (new BigDecimal(refundFee).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                refundResult.setRefundFee(amountPay);
                String refundTime;
                if (status.equals(Status.SUCCESS)) {
                    result.setSuccess(Boolean.TRUE);
                    refundTime = refund.getSuccessTime();
                } else if (status.equals(Status.ABNORMAL)) {
                    result.error("退款异常，请联系管理员", Constants.PAY_FAIL_CODE);
                    return result;
                } else {
                    result.setSuccess(Boolean.TRUE);
                    refundTime = refund.getCreateTime();
                }
                refundResult.setRefundTime(DateUtil.format(DateUtil.parse(refundTime, TIME_FORMAT), DatePattern.NORM_DATETIME_PATTERN));
                result.setResult(JSONUtil.toJsonStr(refundResult));
            } else {
                result.error("退款异常，请联系管理员", Constants.PAY_FAIL_CODE);
            }
        } catch (Exception e) {
            result.errorWithException("退款异常，请联系管理员", Constants.PAY_ERROR_CODE, e);
        }
        return result;
    }
}
